package com.adan.auth.service.impl;

import com.adan.auth.mapper.XcUserMapper;
import com.adan.auth.mapper.XcUserRoleMapper;
import com.adan.auth.model.dto.AuthParamsDto;
import com.adan.auth.model.dto.XcUserExt;
import com.adan.auth.model.po.XcUser;
import com.adan.auth.model.po.XcUserRole;
import com.adan.auth.service.AuthService;
import com.adan.auth.service.WxAuthService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;

/**
 * @version: 1.0
 * @Author: adan
 * @description:
 * @date: 2023-06-24 16:32
 */
@Service("wx_authservice")
public class WxAuthServiceImpl implements AuthService , WxAuthService {
    @Resource
    XcUserMapper xcUserMapper;
    @Resource
    RestTemplate restTemplate;
    @Resource
    XcUserRoleMapper xcUserRoleMapper;
    @Resource
    WxAuthServiceImpl authServiceProxy;

    @Value("${weixin.appid}")
    String appid;
    @Value("${weixin.secret}")
    String secret;
    /**
     * 微信扫码认证，不需要校验密码和验证码
     *
     * @param authParamsDto 认证参数
     * @return
     */
    @Override
    public XcUserExt execute(AuthParamsDto authParamsDto) {
        // 账号
        String username = authParamsDto.getUsername();
        XcUser user = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getUsername, username));
        if (user == null) {
            throw new RuntimeException("账号不存在");
        }
        XcUserExt xcUserExt = new XcUserExt();
        BeanUtils.copyProperties(user, xcUserExt);
        return xcUserExt;
    }

    @Override
    public XcUser wxAuth(String code) {
        // 1.申请令牌、(通过code获取access_token)
        Map<String, String> access_token_map = getAccess_token(code);
        if (access_token_map == null){
            return null;
        }
        String openid = access_token_map.get("openid");
        String accessToken = access_token_map.get("access_token");
        // 2.携带令牌获取用户信息、
        Map<String, String> userinfo = getUserinfo(accessToken, appid);
        if (userinfo == null){
            return null;
        }
        // 3.保存用户信息到数据库
        XcUser user = authServiceProxy.addWxUser(userinfo);

        return user;
    }

    /**
     * 申请访问令牌,响应示例
     * 通过code获取access_token
     {
     "access_token":"ACCESS_TOKEN",
     "expires_in":7200,
     "refresh_token":"REFRESH_TOKEN",
     "openid":"OPENID",
     "scope":"SCOPE",
     "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
     }
     */
    private Map<String, String> getAccess_token(String code) {
        String wxUrl_template = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
                "appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        //请求微信地址
        String wx_uri = String.format(wxUrl_template, appid, secret, code);
        // 调用微信接口申请令牌
        ResponseEntity<String> response = restTemplate.exchange(wx_uri, HttpMethod.POST, null, String.class);
        String result = response.getBody();
        Map<String, String> map = JSON.parseObject(result, Map.class);
        return map;
    }

    /**
     * 携带令牌获取用户信息
     * @param access_token 访问令牌
     * @param openid 普通用户的标识，对当前开发者帐号唯一
     * @return
     * 响应参数
     * {
     * "openid":"OPENID",
     * "nickname":"NICKNAME",
     * "sex":1,
     * "province":"PROVINCE",
     * "city":"CITY",
     * "country":"COUNTRY",
     * "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
     * "privilege":[
     * "PRIVILEGE1",
     * "PRIVILEGE2"
     * ],
     * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
     *
     * }
     */
    private Map<String,String> getUserinfo(String access_token,String openid){
        String wx_uri_template = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
        //请求微信地址
        String wx_uri = String.format(wx_uri_template, access_token, openid);
        // 调用微信接口申请令牌
        ResponseEntity<String> response = restTemplate.exchange(wx_uri, HttpMethod.GET, null, String.class);
        //防止乱码进行转码
        String result = new String(response.getBody().getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
        Map<String, String> map = JSON.parseObject(result, Map.class);

        return map;
    }

    /**
     * 保存用户信息数据库
     * @param user_info_map 用户信息
     * @return
     */
    @Transactional
    public XcUser addWxUser(Map<String, String> user_info_map){
        // 1. 获取用户唯一标识：unionid作为用户的唯一表示
        String unionid = user_info_map.get("unionid");
        // 2. 根据唯一标识，判断数据库是否存在该用户
        XcUser xcUser = xcUserMapper.selectOne(new LambdaQueryWrapper<XcUser>().eq(XcUser::getWxUnionid, unionid));
        // 2.1 存在，则直接返回
        if (xcUser != null){
            return xcUser;
        }
        // 2.2 不存在，新增
        xcUser = new XcUser();
        // 2.3 设置主键
        String uuid = UUID.randomUUID().toString();
        xcUser.setId(uuid);
        // 2.4 设置其他数据库非空约束的属性
        xcUser.setUsername(unionid);
        xcUser.setPassword(unionid);
        xcUser.setWxUnionid(unionid);
        xcUser.setNickname(user_info_map.get("nickname"));
        xcUser.setUserpic(user_info_map.get("headimgurl"));
        xcUser.setName(user_info_map.get("nickname"));
        xcUser.setUtype("101001");  // 学生类型
        xcUser.setStatus("1");
        xcUser.setCreateTime(LocalDateTime.now());
        // 2.5 添加到数据库
        xcUserMapper.insert(xcUser);
        // 3. 添加用户信息到用户角色表
        XcUserRole xcUserRole = new XcUserRole();
        xcUserRole.setId(uuid);
        xcUserRole.setUserId(uuid);
        xcUserRole.setRoleId("17");
        xcUserRole.setCreateTime(LocalDateTime.now());
        xcUserRoleMapper.insert(xcUserRole);
        return xcUser;
    }
}
